/*-----------------------------------------------------------------------------

 Copyright 2017 Hopsan Group

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.


 The full license is available in the file LICENSE.
 For details about the 'Hopsan Group' or information about Authors and
 Contributors see the HOPSANGROUP and AUTHORS files that are located in
 the Hopsan source code root directory.

-----------------------------------------------------------------------------*/

#ifndef AEROPROPELLER_HPP_INCLUDED
#define AEROPROPELLER_HPP_INCLUDED

#include <iostream>
#include "ComponentEssentials.h"
#include "ComponentUtilities.h"
#include "math.h"

//!
//! @file AeroPropeller.hpp
//! @author Petter Krus <petter.krus@liu.se>
//! @date Thu 12 Feb 2015 20:22:02
//! @brief Model of a propeller
//! @ingroup AeroComponents
//!
//==This code has been autogenerated using Compgen==
//from 
/*{, C:, HopsanTrunk, componentLibraries, defaultLibrary, Special, \
AeroComponents}/AeroPropeller.nb*/

using namespace hopsan;

class AeroPropeller : public ComponentC
{
private:
     double dp;
     double b1;
     double b2;
     double g1;
     double g2;
     double ct0;
     double cp0;
     double k;
     Port *mpPmr1;
     double delayParts1[9];
     double delayParts2[9];
     double delayParts3[9];
     Matrix jacobianMatrix;
     Vec systemEquations;
     Matrix delayedPart;
     int i;
     int iter;
     int mNoiter;
     double jsyseqnweight[4];
     int order[2];
     int mNstep;
     //Port Pmr1 variable
     double tormr1;
     double thetamr1;
     double wmr1;
     double cmr1;
     double Zcmr1;
     double eqInertiamr1;
//==This code has been autogenerated using Compgen==
     //inputVariables
     double Up;
     double rho;
     //outputVariables
     double thrust;
     double torque;
     double Pin;
     double Pout;
     double Jp;
     //Expressions variables
     //Port Pmr1 pointer
     double *mpND_tormr1;
     double *mpND_thetamr1;
     double *mpND_wmr1;
     double *mpND_cmr1;
     double *mpND_Zcmr1;
     double *mpND_eqInertiamr1;
     //Delay declarations
//==This code has been autogenerated using Compgen==
     //inputVariables pointers
     double *mpUp;
     double *mprho;
     //inputParameters pointers
     double *mpdp;
     double *mpb1;
     double *mpb2;
     double *mpg1;
     double *mpg2;
     double *mpct0;
     double *mpcp0;
     double *mpk;
     //outputVariables pointers
     double *mpthrust;
     double *mptorque;
     double *mpPin;
     double *mpPout;
     double *mpJp;
     Delay mDelayedPart10;
     Delay mDelayedPart20;
     EquationSystemSolver *mpSolver;

public:
     static Component *Creator()
     {
        return new AeroPropeller();
     }

     void configure()
     {
//==This code has been autogenerated using Compgen==

        mNstep=9;
        jacobianMatrix.create(2,2);
        systemEquations.create(2);
        delayedPart.create(3,6);
        mNoiter=2;
        jsyseqnweight[0]=1;
        jsyseqnweight[1]=0.67;
        jsyseqnweight[2]=0.5;
        jsyseqnweight[3]=0.5;


        //Add ports to the component
        mpPmr1=addPowerPort("Pmr1","NodeMechanicRotational");
        //Add inputVariables to the component
            addInputVariable("Up","Air speed","m/s",1.25,&mpUp);
            addInputVariable("rho","Air density","kg/m3",1.25,&mprho);

        //Add inputParammeters to the component
            addInputVariable("dp", "Propeller diameter", "m", 1.,&mpdp);
            addInputVariable("b1", "Propeller thrust coefficient", "", \
0.2,&mpb1);
            addInputVariable("b2", "Propeller thrust coefficient", "", \
0.2,&mpb2);
            addInputVariable("g1", "Propeller torque coefficient", "", \
0.205,&mpg1);
            addInputVariable("g2", "Propeller torque coefficient", "", \
0.2,&mpg2);
            addInputVariable("ct0", "Propeller torque coefficient", "", \
0.12,&mpct0);
            addInputVariable("cp0", "Propeller torque coefficient", "", \
0.08,&mpcp0);
            addInputVariable("k", "exponent for transition", "", 4,&mpk);
        //Add outputVariables to the component
            addOutputVariable("thrust","Thrust","N",500.,&mpthrust);
            addOutputVariable("torque","Torque","N",0.,&mptorque);
            addOutputVariable("Pin","Input power","W",0.,&mpPin);
            addOutputVariable("Pout","Output Power","W",0.,&mpPout);
            addOutputVariable("Jp","Advance rate"," ",0.,&mpJp);

//==This code has been autogenerated using Compgen==
        //Add constantParameters
        mpSolver = new EquationSystemSolver(this,2);
     }

    void initialize()
     {
        //Read port variable pointers from nodes
        //Port Pmr1
        mpND_tormr1=getSafeNodeDataPtr(mpPmr1, \
NodeMechanicRotational::Torque);
        mpND_thetamr1=getSafeNodeDataPtr(mpPmr1, \
NodeMechanicRotational::Angle);
        mpND_wmr1=getSafeNodeDataPtr(mpPmr1, \
NodeMechanicRotational::AngularVelocity);
        mpND_cmr1=getSafeNodeDataPtr(mpPmr1, \
NodeMechanicRotational::WaveVariable);
        mpND_Zcmr1=getSafeNodeDataPtr(mpPmr1, \
NodeMechanicRotational::CharImpedance);
        mpND_eqInertiamr1=getSafeNodeDataPtr(mpPmr1, \
NodeMechanicRotational::EquivalentInertia);

        //Read variables from nodes
        //Port Pmr1
        tormr1 = (*mpND_tormr1);
        thetamr1 = (*mpND_thetamr1);
        wmr1 = (*mpND_wmr1);
        cmr1 = (*mpND_cmr1);
        Zcmr1 = (*mpND_Zcmr1);
        eqInertiamr1 = (*mpND_eqInertiamr1);

        //Read inputVariables from nodes
        Up = (*mpUp);
        rho = (*mprho);

        //Read inputParameters from nodes
        dp = (*mpdp);
        b1 = (*mpb1);
        b2 = (*mpb2);
        g1 = (*mpg1);
        g2 = (*mpg2);
        ct0 = (*mpct0);
        cp0 = (*mpcp0);
        k = (*mpk);

        //Read outputVariables from nodes
        thrust = (*mpthrust);
        torque = (*mptorque);
        Pin = (*mpPin);
        Pout = (*mpPout);
        Jp = (*mpJp);

//==This code has been autogenerated using Compgen==


        //Initialize delays

        delayedPart[1][1] = delayParts1[1];
        delayedPart[2][1] = delayParts2[1];
     }
    void simulateOneTimestep()
     {
        Vec stateVar(2);
        Vec stateVark(2);
        Vec deltaStateVar(2);

        //Read variables from nodes
        //Port Pmr1
        tormr1 = (*mpND_tormr1);
        thetamr1 = (*mpND_thetamr1);
        wmr1 = (*mpND_wmr1);
        eqInertiamr1 = (*mpND_eqInertiamr1);

        //Read inputVariables from nodes
        Up = (*mpUp);
        rho = (*mprho);

        //Read inputParameters from nodes
        dp = (*mpdp);
        b1 = (*mpb1);
        b2 = (*mpb2);
        g1 = (*mpg1);
        g2 = (*mpg2);
        ct0 = (*mpct0);
        cp0 = (*mpcp0);
        k = (*mpk);

        //LocalExpressions

        //Initializing variable vector for Newton-Raphson
        stateVark[0] = thrust;
        stateVark[1] = cmr1;

        //Iterative solution using Newton-Rapshson
        for(iter=1;iter<=mNoiter;iter++)
        {
         //Propeller
         //Differential-algebraic system of equation parts

          //Assemble differential-algebraic equations
          systemEquations[0] =thrust + \
(Power(dp,3)*rho*(0.025330295910584444*b2*Up + b1*dp*(-2.5330295910584445e-7 \
- 0.004031441804149936*wmr1))*Power(wmr1,2)*Power(1/(Power(1/ct0,k) + \
Power(Abs(b1 - (1.*b2*Up)/(0.00001*dp + \
0.15915494309189535*dp*wmr1)),-k)),1/k))/((0.00001 + \
0.15915494309189535*wmr1)*Abs(b1 - (1.*b2*Up)/(0.00001*dp + \
0.15915494309189535*dp*wmr1)));
          systemEquations[1] =cmr1 + \
(Power(dp,4)*rho*(0.004031441804149936*g2*Up + dp*g1*(-4.031441804149937e-8 - \
0.000641623890917771*wmr1))*Power(wmr1,2)*Power(1/(Power(1/cp0,k) + \
Power(Abs(g1 - (1.*g2*Up)/(0.00001*dp + \
0.15915494309189535*dp*wmr1)),-k)),1/k))/((0.00001 + \
0.15915494309189535*wmr1)*Abs(g1 - (1.*g2*Up)/(0.00001*dp + \
0.15915494309189535*dp*wmr1)));

          //Jacobian matrix
          jacobianMatrix[0][0] = 1;
          jacobianMatrix[0][1] = 0.*Power(1/(Power(1/ct0,k) + Power(Abs(b1 - \
(1.*b2*Up)/(0.00001*dp + 0.15915494309189535*dp*wmr1)),-k)),1/k);
          jacobianMatrix[1][0] = 0.*Power(1/(Power(1/cp0,k) + Power(Abs(g1 - \
(1.*g2*Up)/(0.00001*dp + 0.15915494309189535*dp*wmr1)),-k)),1/k);
          jacobianMatrix[1][1] = 1 + 0.*Power(1/(Power(1/cp0,k) + \
Power(Abs(g1 - (1.*g2*Up)/(0.00001*dp + \
0.15915494309189535*dp*wmr1)),-k)),1/k);
//==This code has been autogenerated using Compgen==

          //Solving equation using LU-faktorisation
          mpSolver->solve(jacobianMatrix, systemEquations, stateVark, iter);
          thrust=stateVark[0];
          cmr1=stateVark[1];
          //Expressions
          torque = cmr1;
          Zcmr1 = (0.0080629*Power(dp,5)*mTimestep*rho*(g1 - \
(g2*Up)/(dp*(0.00001 + 0.159155*wmr1)))*wmr1*Power(1/(Power(1/cp0,k) + \
Power(Abs(g1 - (g2*Up)/(dp*(0.00001 + 0.159155*wmr1))),-k)),1/k))/Abs(g1 - \
(g2*Up)/(dp*(0.00001 + 0.159155*wmr1)));
          Pin = cmr1*wmr1;
          Pout = thrust*Up;
          Jp = Up/(dp*(0.00001 + 0.159155*wmr1));
        }

        //Calculate the delayed parts

        delayedPart[1][1] = delayParts1[1];
        delayedPart[2][1] = delayParts2[1];

        //Write new values to nodes
        //Port Pmr1
        (*mpND_cmr1)=cmr1;
        (*mpND_Zcmr1)=Zcmr1;
        //outputVariables
        (*mpthrust)=thrust;
        (*mptorque)=torque;
        (*mpPin)=Pin;
        (*mpPout)=Pout;
        (*mpJp)=Jp;

        //Update the delayed variabels

     }
    void deconfigure()
    {
        delete mpSolver;
    }
};
#endif // AEROPROPELLER_HPP_INCLUDED
